/*********************************************************************
 * Módulo 3. Tutorial de desarrollo con NME. OfficeBasket MiniGame
 * Programación Multimedia y Juegos
 * Autor: David Vallejo Fernández    david.vallejo@tegnix.com
 * Autor: Carlos González Morcillo   carlos.gonzalez@tegnix.com
 *
 * You can redistribute and/or modify this file under the terms of the
 * GNU General Public License ad published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * and later version. See <http://www.gnu.org/licenses/>.
 *
 * This file is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.  
 *********************************************************************/

package;

import physic.PhPaperBall;
import physic.PhPaperBin;
import graphics.VectorArrow;
import graphics.sprites.Sky;
import util.FpsLabel;
import util.ScoreBoard;

import aze.display.TileLayer;
import aze.display.TileSprite;
import aze.display.SparrowTilesheet;
import nme.Assets;
import nme.display.Sprite;
import nme.events.Event;
import nme.events.MouseEvent;
import nme.Lib;

import phx.World;
import phx.col.AABB;
import phx.col.SortedList;
import phx.Shape;

class OfficeBasket extends Sprite{
  var _layerSky:TileLayer;          // Capa para el fondo         
  var _layerPaper:TileLayer;        // Capa para la bola papel
  var _layerArrow:TileLayer;        // Capa para la flecha
  var _layerBin:TileLayer;          // Capa para la papelera

  var _scoreBoard:ScoreBoard;       // Actualiza los puntos
  var _world:World;                 // Mundo de simulación física
  var _fpsText:FpsLabel;            // Muestra los FPS
  var _previousTime:Int;            // Tiempo desde lanzamiento
  var _sw:Int; var _sh:Int;         // Ancho y alto de la pantalla
  var _spx:Float; var _spy:Float;   // Coordenadas de la bola
  var _ball:PhPaperBall = null;     // Objeto para la bola
  var _bin:PhPaperBin = null;       // Objeto para la papelera
  var _arrow:VectorArrow;           // Clase para dibujar flecha

  // Constructor ==================================================
  public function new() {
    super(); haxe.Timer.delay(init, 150);
  }
	

  function init():Void {
    loadResources();                  // Carga de recursos gráficos
    generateRandomPaperPosition();    // Genera posición para papel
    createPhysicWorld();              // Creación del mundo físico
    createArrow(_spx, _spy);          
    createBasket(_sw, _sh);
    addListeners();
    _previousTime = Lib.getTimer();   // Inicializa el tiempo
  }

  function addListeners():Void {
    Lib.current.stage.addEventListener(MouseEvent.CLICK, onMouseClick);
    Lib.current.stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
    Lib.current.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
  }

  // Crear Fondo ==================================================
  function createBackground(tilesheet:SparrowTilesheet):Void {
    _layerSky = new TileLayer(tilesheet);  
    addChild(_layerSky.view); 
    var background = new Sky("background");
    _layerSky.addChild(background);
    background.update(_sw, _sh);
  }

  // Carga de Recursos ============================================
  function loadResources():Void {
    var sheetData:String = Assets.getText("assets/tiles.xml");
    var tilesheet:SparrowTilesheet = new SparrowTilesheet
      (Assets.getBitmapData("assets/tiles.png"), sheetData);
    _sw = stage.stageWidth; _sh = stage.stageHeight;
    createBackground(tilesheet);
    _layerPaper = new TileLayer(tilesheet);  
    _layerBin = new TileLayer(tilesheet);  
    _layerArrow = new TileLayer(tilesheet);
    _fpsText = new FpsLabel(665, 300, 0x000000, "assets/cafeta.ttf");  
    _scoreBoard = new ScoreBoard(660,225,0xffffff,"assets/cafeta.ttf");

    addChild(_layerPaper.view); 
    addChild(_layerBin.view); 
    addChild(_layerArrow.view); 
    addChild(_fpsText);
    addChild(_scoreBoard);
  }

  // Métodos Auxiliares ===========================================
  function generateRandomPaperPosition():Void {
    _spx =_sw/2 - 50 + Std.random(Std.int(_sw/2));
    _spy = 50 + Std.random(Std.int(_sh/3));
  }

  function createArrow(px:Float, py:Float):Void {
    _arrow = new VectorArrow(_layerArrow, "ball", "dot", "arrow", 
			     px, py, 10, 100);
  }

  function createBasket(w:Float, h:Float):Void {
    var xaux = 50+ Std.random(Std.int(w/2));
    _bin = new PhPaperBin("basket", _layerBin, _world, xaux, h-52);
  }

  // Physic World =================================================
  function createPhysicWorld():Void {
    var size = new AABB(-1000, -1000, 1000, 1000);
    var bp = new SortedList();
    _world = new World(size, bp);
    createLimits(_sw, _sh);    
    _world.gravity = new phx.Vector(0,0.9);
  }

  function createLimits(w:Float, h:Float):Void {
    // Creamos los límites del mundo: makeBox(Ancho, Alto, X, Y)
    // La X e Y de la caja tiene origen en esquina superior izqda.
    var s = Shape.makeBox(w,200,0,h-20);
    s.material.restitution = 0.2;  // Establecemos propiedades 
    s.material.density = 9;        //  en el material...
    _world.addStaticShape(s);
    _world.addStaticShape(Shape.makeBox(w,200,0,-200)); 
    _world.addStaticShape(Shape.makeBox(200,h,-200,0));
    _world.addStaticShape(Shape.makeBox(200,h,w,0));
  }

  // Update =======================================================
  function onEnterFrame(e:Event):Void {
    var now = Lib.getTimer();
    var secondsSinceClick = (now - _previousTime)/1000.0;   

    _world.step(1,20);
    if (_ball != null) {       // Si hay bola (usuario hizo click)
      _ball.update(_sw, _sh);  // Actualizamos la bola!
      if (secondsSinceClick > 2) {   // Si han pasado más de 2 seg
	// Comprobamos si la bola está tocando con el objeto
	// que define la base de la papelera...
	if (_ball.checkCollision(_bin.getIdBase()))   
	  _scoreBoard.update(1);
	_ball.destroy(); _ball = null;
	generateRandomPaperPosition();  // Nueva posición!!
	_arrow.setBasePos(_spx, _spy);  // Actualizar flecha
      }
    }
    // Solo actualizamos la flecha si no hay bola activa...
    else { _arrow.update();  _layerArrow.render(); }

    _layerSky.render(); _layerPaper.render(); _layerBin.render(); 
    _fpsText.update(); 
  }
  
  // Events =======================================================
  function onMouseClick(e:MouseEvent):Void {
    if (_ball == null) // Si no hay pelota activa, creamos una
      _ball = new PhPaperBall("ball", _layerPaper, _world, 
			      _spx, _spy, _arrow.getVector());
    _previousTime = Lib.getTimer();
  }

  function onMouseMove(event:MouseEvent):Void {
    _arrow.setArrowPos(event.localX, event.localY);
  }

  // Main =========================================================
  public function main() {
    Lib.current.addChild(new OfficeBasket());
  }
}
